﻿using SoundSynthLab.Data;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Display;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// Pour en savoir plus sur le modèle d'élément Page fractionnée, consultez la page http://go.microsoft.com/fwlink/?LinkId=234234

namespace SoundSynthLab
{
    /// <summary>
    /// Page affichant un titre de groupe, la liste des éléments d'un groupe et les détails concernant
    /// l'élément actuellement sélectionné.
    /// </summary>
    public sealed partial class SplitPage : SoundSynthLab.Common.LayoutAwarePage
    {
        public SplitPage()
        {
            this.InitializeComponent();
        }

        #region Gestion d'état de page

        /// <summary>
        /// Remplit la page à l'aide du contenu passé lors de la navigation. Tout état enregistré est également
        /// fourni lorsqu'une page est recréée à partir d'une session antérieure.
        /// </summary>
        /// <param name="navigationParameter">Valeur de paramètre passée à
        /// <see cref="Frame.Navigate(Type, Object)"/> lors de la requête initiale de cette page.
        /// </param>
        /// <param name="pageState">Dictionnaire d'état conservé par cette page durant une session
        /// antérieure. Null lors de la première visite de la page.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            // TODO: créez un modèle de données approprié pour le domaine posant problème pour remplacer les exemples de données
            var group = SampleDataSource.GetGroup((String)navigationParameter);
            this.DefaultViewModel["Group"] = group;
            this.DefaultViewModel["Items"] = group.Items;

            if (pageState == null)
            {
                this.itemListView.SelectedItem = null;
                // Quand il s'agit d'une nouvelle page, sélectionne automatiquement le premier élément, sauf si la navigation
                // de page logique est utilisée (voir #region navigation de page logique ci-dessous.)
                if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
                {
                    this.itemsViewSource.View.MoveCurrentToFirst();
                }
            }
            else
            {
                // Restaure l'état précédemment enregistré associé à cette page
                if (pageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
                {
                    var selectedItem = SampleDataSource.GetItem((String)pageState["SelectedItem"]);
                    this.itemsViewSource.View.MoveCurrentTo(selectedItem);
                }
            }
        }

        /// <summary>
        /// Conserve l'état associé à cette page en cas de suspension de l'application ou de la
        /// suppression de la page du cache de navigation. Les valeurs doivent être conformes aux
        /// exigences en matière de sérialisation de <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="pageState">Dictionnaire vide à remplir à l'aide de l'état sérialisable.</param>
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
            if (this.itemsViewSource.View != null)
            {
                var selectedItem = (SampleDataItem)this.itemsViewSource.View.CurrentItem;
                if (selectedItem != null) pageState["SelectedItem"] = selectedItem.UniqueId;
            }
        }

        #endregion

        #region Navigation entre pages logiques

        // En général, la gestion de l'état visuel présente directement les quatre états d'affichage d'application
        // (mode Landscape ou Portait plein écran, ainsi que les affichages Snapped et Fill). La page fractionnée est
        // conçue pour que les états d'affichage Snapped et Portrait possèdent chacun deux sous-états distincts :
        // soit la liste d'éléments, soit les détails sont affichés, mais pas les deux à la fois.
        //
        // Le tout est implémenté à l'aide d'une seule page physique pouvant représenter deux pages logiques.
        // Le code ci-dessous parvient à ce but sans que l'utilisateur ne se rende compte de
        // la distinction.

        /// <summary>
        /// Invoqué pour déterminer si la page doit agir en tant qu'une ou deux pages logiques.
        /// </summary>
        /// <param name="viewState">État d'affichage faisant l'objet de la requête, ou Null
        /// pour l'état d'affichage actuel. Ce paramètre est facultatif et sa valeur par défaut est Null.
        /// </param>
        /// <returns>True lorsque l'état d'affichage faisant l'objet de la requête a la valeur Portrait ou Snapped, sinon False
        /// .</returns>
        private bool UsingLogicalPageNavigation(ApplicationViewState? viewState = null)
        {
            if (viewState == null) viewState = ApplicationView.Value;
            return viewState == ApplicationViewState.FullScreenPortrait ||
                viewState == ApplicationViewState.Snapped;
        }

        /// <summary>
        /// Invoqué lorsqu'un élément d'une liste est sélectionné.
        /// </summary>
        /// <param name="sender">GridView (ou ListView lorsque l'état d'affichage de l'application est Snapped)
        /// affichant l'élément sélectionné.</param>
        /// <param name="e">Données d'événement décrivant la façon dont la sélection a été modifiée.</param>
        void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Invalidez l'état d'affichage lorsque la navigation entre pages logiques est en cours, car une modification
            // apportée à la sélection pourrait entraîner la modification de la page logique active correspondante. Lorsqu'un
            // élément est sélectionné, l'affichage passe de la liste d'éléments
            // aux détails concernant l'élément sélectionné. Lorsque cet élément est désélectionné, l'effet inverse
            // est produit.
            if (this.UsingLogicalPageNavigation()) this.InvalidateVisualState();
        }

        /// <summary>
        /// Invoqué lorsque l'utilisateur clique sur le bouton Précédent.
        /// </summary>
        /// <param name="sender">Instance du bouton Précédent.</param>
        /// <param name="e">Données d'événement décrivant la façon dont l'utilisateur a cliqué sur le bouton Précédent.</param>
        protected override void GoBack(object sender, RoutedEventArgs e)
        {
            if (this.UsingLogicalPageNavigation() && itemListView.SelectedItem != null)
            {
                // Lorsque la navigation entre pages logiques est en cours et qu'un élément est sélectionné,
                // les détails concernant cet élément sont affichés. La désélection de cet élément aura pour effet le retour
                // à l'affichage de la liste d'éléments. Il s'agit, du point de vue de l'utilisateur, d'une navigation
                // de logique inversée.
                this.itemListView.SelectedItem = null;
            }
            else
            {
                // Lorsqu'aucune navigation entre pages logiques n'est en cours et qu'aucun élément
                // n'est sélectionné, utilisez le comportement de bouton Précédent par défaut.
                base.GoBack(sender, e);
            }
        }

        /// <summary>
        /// Invoqué pour déterminer le nom de l'état visuel correspondant à l'état d'affichage
        /// d'une application.
        /// </summary>
        /// <param name="viewState">État d'affichage faisant l'objet de la requête.</param>
        /// <returns>Nom de l'état visuel désiré. Il s'agit du même nom que celui
        /// de l'état d'affichage, sauf si un élément est sélectionné dans l'affichage Portrait ou Snapped où
        /// cette page logique supplémentaire est représentée par l'ajout du suffixe _Detail.</returns>
        protected override string DetermineVisualState(ApplicationViewState viewState)
        {
            // Modifiez l'état d'activation du bouton Précédent lorsque l'état d'affichage est modifié
            var logicalPageBack = this.UsingLogicalPageNavigation(viewState) && this.itemListView.SelectedItem != null;
            var physicalPageBack = this.Frame != null && this.Frame.CanGoBack;
            this.DefaultViewModel["CanGoBack"] = logicalPageBack || physicalPageBack;

            // Détermine l'état visuel des dispositions en mode Paysage, en fonction non pas de l'état de l'affichage, mais
            // de la largeur de la fenêtre. Cette page a une disposition appropriée pour
            // 1366 pixels virtuels ou une largeur supérieure, et une autre pour les écrans plus étroits ou lorsqu'une application
            // ancrée réduit l'espace horizontal disponible à moins de 1366.
            if (viewState == ApplicationViewState.Filled ||
                viewState == ApplicationViewState.FullScreenLandscape)
            {
                var windowWidth = Window.Current.Bounds.Width;
                if (windowWidth >= 1366) return "FullScreenLandscapeOrWide";
                return "FilledOrNarrow";
            }

            // En mode Portrait ou en cas d'ancrage, commence par le nom de l'état visuel par défaut, puis ajoute un
            // suffixe lors de l'affichage des détails au lieu de la liste
            var defaultStateName = base.DetermineVisualState(viewState);
            return logicalPageBack ? defaultStateName + "_Detail" : defaultStateName;
        }

        #endregion
    }
}
